﻿namespace NTLib.Pipe.UTest
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using NTLib.Pipe.Targets;
    using NTLib.Core.Threading;
    using NTLib.Core.Tasks;
    using NTLib.Pipe.UTest.TestData;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using NTLib.Pipe.Exceptions;
    using NTLib.Pipe.Providers;
    using NTLib.Pipe.Descriptors;

    [TestClass]
    public class PipeManagerUTest
    {
        #region Methods

        [ExpectedException(typeof(NoProviderRegisterException))]
        [TestCategory("Pipe")]
        [TestMethod]
        public void PipeManager_NoProvider()
        {
            using (new TestPipeManager())
            {
                try
                {
                    PipeManager.Instance.CreateAsync<DataStruct>(LocalTargetDescription.Instance).Wait();
                }
                catch (AggregateException ex)
                {
                    throw ex.InnerException;
                }
            }
        }

        [ExpectedException(typeof(NoProviderRegisterException))]
        [TestCategory("Pipe")]
        [TestMethod]
        public void PipeManager_RegisterUnRegister()
        {
            using (new TestPipeManager())
            {
                var prov = new MemoryProvider();
                PipeManager.Instance.Register(prov);

                var res = PipeManager.Instance.CreateAsync<DataStruct>(LocalTargetDescription.Instance, PipeType.TwoWay).WaitResult();
                Assert.IsNotNull(res);

                PipeManager.Instance.UnRegister(prov.Id);
                try
                {
                    PipeManager.Instance.CreateAsync<DataStruct>(LocalTargetDescription.Instance, PipeType.TwoWay).WaitResult();
                }
                catch (AggregateException ex)
                {
                    throw ex.InnerException;
                }
            }
        }

        [TestCategory("Pipe")]
        [TestMethod]
        public void PipeManager_TwoWay()
        {
            using (new TestPipeManager())
            {
                var prov = new MemoryProvider();
                try
                {
                    PipeManager.Instance.Register(prov);


                    var g = Guid.NewGuid();
                    DataStruct data = new DataStruct();
                    data.Data = g.ToString();
                    using (var pipe = PipeManager.Instance.CreateAsync<DataStruct>(LocalTargetDescription.Instance, PipeType.TwoWay).WaitResult())
                    {
                        var readPipe = PipeManager.Instance.GetPipeAsync<DataStruct>(pipe.Id).WaitResult();

                        pipe.SendAsync(data).Wait();

                        var read = readPipe.PopAsync().WaitResult();
                        Assert.AreNotEqual(read, null);
                        Assert.AreEqual(read.Data, g.ToString());

                        g = Guid.NewGuid();
                        data.Data = g.ToString();

                        readPipe.SendAsync(data).Wait();

                        read = pipe.PopAsync().WaitResult();
                        Assert.AreNotEqual(read, null);
                        Assert.AreEqual(read.Data, g.ToString());
                    }
                }
                finally
                {
                    PipeManager.Instance.UnRegister(prov.Id);
                }
            }
        }

        [TestCategory("Pipe")]
        [TestMethod]
        public void PipeManager_OneWay()
        {
            using (new TestPipeManager())
            {
                var prov = new MemoryProvider();
                try
                {
                    PipeManager.Instance.Register(prov);

                    var g = Guid.NewGuid();
                    DataStruct data = new DataStruct();
                    data.Data = g.ToString();
                    using (var pipe = PipeManager.Instance.CreateAsync<DataStruct>(LocalTargetDescription.Instance, PipeType.OneWay).WaitResult())
                    {
                        var readPipe = PipeManager.Instance.GetPipeAsync<DataStruct>(pipe.Id).WaitResult();

                        pipe.SendAsync(data).Wait();

                        var read = readPipe.PopAsync().WaitResult();
                        Assert.AreNotEqual(read, null);
                        Assert.AreEqual(read.Data, g.ToString());
                    }
                }
                finally
                {
                    PipeManager.Instance.UnRegister(prov.Id);
                }
            }
        }


        [TestCategory("Pipe")]
        [TestMethod]
        public void PipeManager_FromTarget()
        {
            using (new TestPipeManager())
            {
                var prov = new MemoryProvider();
                try
                {
                    PipeManager.Instance.Register(prov);

                    var g = Guid.NewGuid();
                    DataStruct data = new DataStruct();
                    data.Data = g.ToString();
                    using (var pipe = PipeManager.Instance.CreateAsync<DataStruct>(LocalTargetDescription.Instance, PipeType.FromTarget).WaitResult())
                    {
                        var readPipe = PipeManager.Instance.GetPipeAsync<DataStruct>(pipe.Id).WaitResult();

                        readPipe.SendAsync(data).Wait();

                        var read = pipe.PopAsync().WaitResult();
                        Assert.AreNotEqual(read, null);
                        Assert.AreEqual(read.Data, g.ToString());
                    }

                }
                finally
                {
                    PipeManager.Instance.UnRegister(prov.Id);
                }
            }
        }
        #endregion
    }
}
